import datetime
import json

from django.core.paginator import Paginator
from django.shortcuts import render
from django import http
from django.views import View
from django_redis import get_redis_connection

from meiduo_mall.utils.categories import get_categories
from meiduo_mall.utils.log import logger_out
from meiduo_mall.utils.response_code import RETCODE
from .models import GoodsCategory, SKU, GoodsVisitCount
from . import constants
from meiduo_mall.utils.breadcrumb import get_breadcrumb


class ListView (View):
    # 商品陈述
    def get(self, request, category_id, page_num):
        # 获取排序参数：查询参数是GET
        receive_sort = request.GET.get('sort', 'default')
        # 获取广告的三级分类：是个字典
        categories = get_categories()
        # 判断category是否能获取ok
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            logger_out.warning(e)
            return http.HttpResponseForbidden("GoodsCategory does not exist!")
        # 获取面包屑
        breadcrumb = get_breadcrumb(category)

        # 面包屑的具体方法
        # cat2 = category.parent
        # cat1 = cat2.parent
        # breadcrumb = {
        #     'cat1': {
        #         'url': cat1.goodschannel_set.all()[0].url,
        #         'name': cat1.name
        #     },
        #     'cat2': cat2,
        #     'cat3': category,
        # }

        # 判断具体的排名
        if receive_sort == 'hot':
            sort_order = '-comments'
        elif receive_sort == 'price':
            sort_order = '-price'
        else:
            sort_order = 'price'

        # 热销排行：通过另外一个视图实现
        # 查询当前页的商品数据
        # 1.查询指定分类的数据, 以comment降序来进行排序
        skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by(sort_order)
        # 2.创建分页器，接受sort排序
        paginator = Paginator(skus, constants.SKU_LIST_PER_PAGE)
        # 3.获取指定页面商品数据
        page_skus = paginator.page(page_num)
        # 4.获取总页数
        total_page = paginator.num_pages
        # carts
        # categories breadcrumb category total_page page_num sort sku
        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'category': category,
            'total_page': total_page,
            'page_num': page_num,
            'sort': receive_sort,
            'page_skus': page_skus,
        }
        return render(request, 'list.html', context)


# 获取热销商品排名
class HotGoodsView (View):
    def get(self, request, category_id):
        try:
            skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by('-sales')[0:3]
        except Exception as e:
            logger_out.warning(e)
            http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '获取排行参数错误！'})
        hot_skus = []
        for sku in skus:
            hot_skus.append({
                'id': sku.id,
                'default_image_url': sku.default_image.url,
                'name': sku.name,
                'price': sku.price,
            })
        return http.JsonResponse({'code': RETCODE.OK,
                                  'errmsg': 'ok',
                                  'hot_sku_list': hot_skus,
                                  })


# 获取详细页面信息
class DetailView (View):
    def get(self, request, sku_id):
        # 获取sku对象
        sku = SKU.objects.get(id=sku_id)
        # 获取三级广告分类
        categories = get_categories()
        # 获取面包屑
        breadcrumb = get_breadcrumb(sku.category)
        # 获取相应的spu对象
        spu = sku.spu
        # 获取热销排行:上面的视图已经处理完成
        # 创建选项和sku.id的映射关系
        skues = spu.sku_set.order_by('id')
        sku_options = {}
        sku_option = []
        for sku_temp in skues:
            infor_temp = []
            for infor in sku_temp.specs.order_by('spec_id'):
                infor_temp.append(infor.option.id)
                if sku_temp.id == sku.id:
                    sku_option.append(infor.option.id)
            sku_options[tuple(infor_temp)] = sku_temp.id
        # 根据产品的规格，选项创建出选项的属性，更改该属性可以再次请求
        specs_list =[]
        specs = spu.specs.order_by('id')
        for index, spec_temp in enumerate(specs):
            option_list = []
            for option in spec_temp.options.order_by('id'):
                option_temp = sku_option[:]
                option_temp[index] = option.id
                option.sku_id = sku_options.get(tuple(option_temp), 0)
                option_list.append(option)
            spec_temp.option_list = option_list
            specs_list.append(spec_temp)

        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'spu': spu,
            'sku_id': sku.id,
            'comments': spu.comments,
            'specs_list': specs_list,
        }

        return render(request, 'detail.html', context)


# 收集拜访者的信息。
class DetailVisitView (View):
    def post(self, request, category_id):
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            logger_out.warning(e)
            return http.HttpResponseForbidden('缺少参数！')
        try:
            goodsvisitcount = GoodsCategory.goodsvisitcount_set.get(date=datetime.datetime.now())
        except Exception as e:
            goodsvisitcount = GoodsVisitCount.objects.create(category_id=category_id, count=1)
        else:
            goodsvisitcount.count += 1
            goodsvisitcount.save()
        return http.JsonResponse({'code': RETCODE.OK,
                                  'errmsg': 'ok'})


# 保存和显示用户的浏览历史记录
class HistroryView (View):
    def post(self, request):
        # 获取用户sku_id
        dict1 = json.loads(request.body.decode())
        sku_id = dict1.get('sku_id')
        user = request.user
        # 验证
        if not user.is_authenticated:
            return http.JsonResponse({'code': RETCODE.USERERR, 'errmsg': '用户未登录'})
        if not all([sku_id]):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数为空'})
        # 处理
        # 思路：利用管道技术处理，存储的列表为user_id,而存储的内容为sku_id
        # 1.必须先判断是否登录，如果没有登录，则提示必须登录，
        key = 'history_%d' % user.id
        redis_cli = get_redis_connection('history')
        # 2.无论用户user_id中sku_id是否存在，都应该先删除再添加
        pipeline = redis_cli.pipeline()
        # 先去重
        pipeline.lrem(key, 0, sku_id)
        # 再添加
        pipeline.lpush(key, sku_id)
        # 注意如果指定了浏览历史的个数需要在此截取列表中的元素
        # 3.执行execute
        pipeline.execute()
        # 最后响应结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})

    def get(self, request):
        # 思路：
        # 判断用户是否登录，如果没有登录，则提示登录
        # 利用管道处理：

        if not request.user.is_authenticated:
            return http.JsonResponse({"code": RETCODE.USERERR, 'errmsg': '用户未登录'})

        # 1. 连接reids
        redis_cli = get_redis_connection('history')
        # 2.通过user_id和history拼接找到sku_id,读取就不需要使用管道
        redis_user_name = 'history_%d' % request.user.id
        sku_id_bytes = redis_cli.lrange(redis_user_name, 0, -1)
        # 3.返回sku_id是二进制，通过推导式转换为整型。利用列表来接受有多个user_id
        sku_id_int = [int(sku_id_byte) for sku_id_byte in sku_id_bytes]
        # 4.拼接返回的列表
        skus = []
        for sku_id in sku_id_int:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'id': sku_id,
            })
        return http.JsonResponse({"code": RETCODE.OK, 'errmsg': 'ok', 'skus': skus})










